#ifndef _OOP_CLOSURE_HPP
#define _OOP_CLOSURE_HPP

class Space;
class Heap;

class HiObject;
class Klass;

template <typename T>
class ArrayList;

template <typename K, typename V>
class Map;

template <typename T>
class Stack;

class OopClosure {
public:
    virtual void do_oop(HiObject** obj) = 0;

    virtual void do_array_list(ArrayList<Klass*>** alist) = 0;
    virtual void do_array_list(ArrayList<HiObject*>** alist) = 0;
    virtual void do_map(Map<HiObject*, HiObject*>** amap) = 0;
    virtual void do_raw_mem(char** mem, int length) = 0;
    virtual void do_klass(Klass** k) = 0;
};

class ScavengeOopClosure : public OopClosure {
private:
    Space* _from;
    Space* _to;
    Space* _meta;

    Stack<HiObject*>* _oop_stack;

    HiObject* copy_and_push(HiObject* obj);

public:
    ScavengeOopClosure(Space* from, Space* to, Space* meta);
    virtual ~ScavengeOopClosure();

    virtual void do_oop(HiObject** oop);

    virtual void do_array_list(ArrayList<Klass*>** alist);
    virtual void do_array_list(ArrayList<HiObject*>** alist);
    virtual void do_map(Map<HiObject*, HiObject*>** amap);
    virtual void do_raw_mem(char** mem, int length);
    // CAUTION : we do not move Klass, because they locate at MetaSpace.
    virtual void do_klass(Klass** k);

    void scavenge();
    void process_roots();
};

#endif
